
/**
 * 初始场景
 * 功能：版本更新、热更新、全局初始化
 */
cc.Class({
    extends: cc.Component,

    properties: {
        lblErr: {
            default: null,
            type: cc.Label
        },

        updateBar: {
            default: null,
            type: cc.ProgressBar
        },

        labPercent: {
            default: null,
            type: cc.Label
        },

        aniLogin: {
            default: null,
            type: cc.Animation
        },

        labLog:cc.Label,//日志

        _failCount:0,//失败重连
        _isUpdate:-1,//是否启动热更新

        manifestUrl: cc.RawAsset,
        _updating: false,
        _canRetry: false,
        _storagePath: '',
        
        socket:"",
        
        //流畅显示进度条
        _prss:0,
        _isLoading:true,
    },

    checkCb: function (event) {
        switch (event.getEventCode())
        {
            case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:
                this.lblErr.string = "No local manifest file found, hot update skipped.";
                this._updating = true;
                break;
            case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:
            case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST:
                this.lblErr.string = "Fail to download manifest file, hot update skipped.";
                this._updating = true;
                break;
            case jsb.EventAssetsManager.ALREADY_UP_TO_DATE:
                this.lblErr.string = "Already up to date with the latest remote version.";
                cc.eventManager.removeListener(this._checkListener);
                this._checkListener = null;
                this._updating = true;
                this.startGame();
                break;
            case jsb.EventAssetsManager.NEW_VERSION_FOUND:
                this.lblErr.string = 'New version found, please try to update.';
                
                this.labPercent.string = '00.00%';
                this.updateBar.progress = 0;
                this._updating = false;
                break;
            default:
                return;
        }
        
        cc.eventManager.removeListener(this._checkListener);
        this._checkListener = null;
        this.hotUpdate(); 
    },

    updateCb: function (event) {
        var needRestart = false;
        var failed = false;
        this._isLoading = false;
       
        switch (event.getEventCode())
        {
            case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:
                this.lblErr.string = 'No local manifest file found, hot update skipped.';
                failed = true;
                break;
            case jsb.EventAssetsManager.UPDATE_PROGRESSION:
                var percent = event.getPercent();
                var percentTemp = percent/100;
                //this.updateBar.progress =percentTemp.toFixed(2);// percentTemp.toFixed(2);//percent/100;
                //this.updateBar.progress = event.getPercentByFile();
                //this.panel.fileLabel.string = event.getDownloadedFiles() + ' / ' + event.getTotalFiles();
                //this.panel.byteLabel.string = event.getDownloadedBytes() + ' / ' + event.getTotalBytes();
                var msg = event.getMessage();
                if (msg) {
                    this.lblErr.string = 'Updated file: ' + msg;
                   
                }
              
                if(!isNaN(percentTemp))
                {
                    this.labPercent.string = percentTemp.toFixed(0) + '%';
                    this.updateBar.progress = (percentTemp/100).toFixed(2);  
                }
                break;
            case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:
            case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST:
                this.lblErr.string = 'Fail to download manifest file, hot update skipped.';
                failed = true;
                break;
            case jsb.EventAssetsManager.ALREADY_UP_TO_DATE:
                this.lblErr.string = 'Already up to date with the latest remote version.';
                failed = true;
                break;
            case jsb.EventAssetsManager.UPDATE_FINISHED:
                this.lblErr.string = 'Update finished. ' + event.getMessage();
                needRestart = true;
                break;
            case jsb.EventAssetsManager.UPDATE_FAILED:
                this.lblErr.string = 'Update failed. ' + event.getMessage();
                this._updating = false;
                this._canRetry = true;
                this._failCount ++;
                if (this._failCount < 5)
                {
                    this.retry();
                }
                else
                {
                    this._failCount = 0;
                    failed = true;
                }
                break;
            case jsb.EventAssetsManager.ERROR_UPDATING:
                this.lblErr.string = 'Asset update error: ' + event.getAssetId() + ', ' + event.getMessage();
                break;
            case jsb.EventAssetsManager.ERROR_DECOMPRESS:
                this.lblErr.string = event.getMessage();
                break;
            default:
                break;
        }

        if (failed) {
            cc.eventManager.removeListener(this._updateListener);
            this._updateListener = null;
            this._updating = false;
            this.lblErr.string = "没有资源更新\n";
            this.startGame();
        }

        if (needRestart) {
            cc.eventManager.removeListener(this._updateListener);
            this._updateListener = null;
            // Prepend the manifest's search path
            var searchPaths = jsb.fileUtils.getSearchPaths();
            var newPaths = this._am.getLocalManifest().getSearchPaths();
            Array.prototype.unshift(searchPaths, newPaths);
            // This value will be retrieved and appended to the default search path during game startup,
            // please refer to samples/js-tests/main.js for detailed usage.
            // !!! Re-add the search paths in main.js is very important, otherwise, new scripts won't take effect.
            cc.sys.localStorage.setItem('HotUpdateSearchPaths', JSON.stringify(searchPaths));
            jsb.fileUtils.setSearchPaths(searchPaths);
            this.lblErr.string = "游戏资源更新完毕\n";
            //cc.audioEngine.stopAll();
            cc.game.restart();
        }
  
    },
    
    update:function(dt){
        this._timer += dt;
        if ( this._timer >= 1.0 ) {
            this._timer = 0;
            this.lblErr.string += "1秒\n";
        }

        if(this._prss <100 && this._isLoading == true)
        {
            this._prss += 1;
            this.labPercent.string = this._prss + '%';
            this.updateBar.progress = (this._prss/100).toFixed(1);  
        }
    },
    
    //失败，重新下载
    retry: function () {
        if (!this._updating && this._canRetry) {
            this._canRetry = false;
            this.lblErr.string = 'Retry failed Assets...';
            this._am.downloadFailedAssets();
        }
    },
    
    //检查更新
    checkUpdate: function () {
        this.currentTime11 = Date.parse(new Date())/1000;
        // Hot update is only available in Native build
        if (!cc.sys.isNative || this._isUpdate == -1) {
              this.startGame();
              return ;
        }

        this.lblErr.string += "检查游戏资源更新...\n";
        if (this._updating) {
            this.lblErr.string = 'Checking or updating ...';
            return ;
        }

        if (this._am.getState() === jsb.AssetsManager.State.UNINITED) {
            this._am.loadLocalManifest(this.manifestUrl);
        }

        if (!this._am.getLocalManifest() || !this._am.getLocalManifest().isLoaded()) {
            this.lblErr.string = 'Failed to load local manifest ...';
            return ;
        }
    
        this._checkListener = new jsb.EventListenerAssetsManager(this._am, this.checkCb.bind(this));
        cc.eventManager.addListener(this._checkListener, 1);

        this._am.checkUpdate();
        this._updating = true;
    },

    //立即更新
    hotUpdate: function () {
        // Hot update is only available in Native build
        if (!cc.sys.isNative || this._isUpdate == -1) {
            this.startGame();
            return false;
        }
       
        if (this._am && !this._updating) {
            this._updateListener = new jsb.EventListenerAssetsManager(this._am, this.updateCb.bind(this));
            cc.eventManager.addListener(this._updateListener, 1);
            if (this._am.getState() === jsb.AssetsManager.State.UNINITED) {
                this._am.loadLocalManifest(this.manifestUrl);
            }
            this._failCount = 0;
            this._am.update();
            this._updating = true;
        }
    },

    //初始化公共对象
    initMgr:function(){
        CL.NET = require("Net");
        CL.NET.ip = this.socket;//长连地址

        CL.SOUND = require("SoundManage");
        CL.SOUND.loadAudio();
    },
    
    startUpdate:function(){
        if (!cc.sys.isNative )
            return;
        this._storagePath = ((jsb.fileUtils ? jsb.fileUtils.getWritablePath() : '/') + 'update/remote-asset');

        // Setup your own version compare handler, versionA and B is versions in string
        // if the return value greater than 0, versionA is greater than B,
        // if the return value equals 0, versionA equals to B,
        // if the return value smaller than 0, versionA is smaller than B.
        var versionCompareHandle = function (versionA, versionB) {
            var vA = versionA.split('.');
            var vB = versionB.split('.');
            for (var i = 0; i < vA.length; ++i) {
                var a = parseInt(vA[i]);
                var b = parseInt(vB[i] || 0);
                if (a === b) {
                    continue;
                }
                else {
                    return a - b;
                }
            }
            if (vB.length > vA.length) {
                return -1;
            }
            else {
                return 0;
            }
        };
      
        // Init with empty manifest url for testing custom manifest
        this._am = new jsb.AssetsManager(this.manifestUrl, this._storagePath, versionCompareHandle);
        if (!cc.sys.ENABLE_GC_FOR_NATIVE_OBJECTS) {
            this._am.retain();
        }

        var lblErr = this.lblErr;
        // Setup the verification callback, but we don't have md5 check function yet, so only print some message
        // Return true if the verification passed, otherwise return false
        this._am.setVerifyCallback(function (path, asset) {
            // When asset is compressed, we don't need to check its md5, because zip file have been deleted.
            var compressed = asset.compressed;
            // Retrieve the correct md5 value.
            var expectedMD5 = asset.md5;
            // asset.path is relative path and path is absolute.
            var relativePath = asset.path;
            // The size of asset file, but this value could be absent.
            var size = asset.size;
            if (compressed) {
                lblErr.string = "Verification passed : " + relativePath;
                return true;
            }
            else {
                lblErr.string = "Verification passed : " + relativePath + ' (' + expectedMD5 + ')';
                return true;
            }
        });

        this.lblErr.string = 'Hot update is ready, please check or directly update.';
        if (cc.sys.os === cc.sys.OS_ANDROID) {
            // Some Android device may slow down the download process when concurrent tasks is too much.
            // The value may not be accurate, please do more test and find what's most suitable for your game.
            this._am.setMaxConcurrentTask(2);
            this.lblErr.string = "Max concurrent tasks count have been limited to 2";
        }
        
        this.updateBar.progress = 0;
    },

    //获取服务器列表，检查是否更新
    getServerUrlList:function(){
        var self = this;
        var initServer = function(ret){
            if(ret.Code == -1)
            {
                self.labLog.string = "连接服务器失败...";
                self.getServerUrlList();
                return;
            }
    
            self.lblErr.string += "收到返回消息\n";
            self._isUpdate = ret.IsUpdate;//1强更 or 0热更 or -1不更
            CL.HTTP.url = ret.WebAPIUrl;//web地址
            CL.HTTP.hotUrl = ret.UpdateUrl;//强更地址
            self.socket = ret.SocketURL;//长连地址
            User.setAppState(ret.Status);
            //"热更地址:" -> ret.HotUpdateUrl
            //self.startGame();
            if(!cc.sys.isNative)
            {
                self._isUpdate = -1;
            }

            if(self._isUpdate == -1 )
            {
                self.startGame();
            }    
            else if(self._isUpdate == 0 )
            {
                self.labLog.string = "发现新的资源，正在更新中...";
                self.checkUpdate();
            }
            else if(self._isUpdate == 1 )
            {
                self.labLog.string = "发现新的版本";
                //PlatformUtils.verUpdata(ret.UpdateUrl);
            }
        };
        var xhr = null;
        var complete = false;

        var fnRequest = function(){
            self.lblErr.string += "正在连接服务器 \n版本号：" + CL.HTTP.version + "\n";
            self.labLog.string = "正在连接服务器...";
            var data = {
                Equipment: Utils.getEquipment(),
                Version: CL.HTTP.version,
            };
            xhr = CL.HTTP.sendRequest(DEFINE.HTTP_MESSAGE.STARTAPP,data,function(ret){
                xhr = null;
                complete = true;
                initServer(ret);
            },"POST");
            setTimeout(fn,3000);            
        }
        
        var fn = function(){
            if(!complete){
                if(xhr){  
                   xhr.abort();
                   self.labLog.string = "连接中...";
                   var str = xhr.status + "：连接失败，即将重试 \n"
                   self.lblErr.string += str;
                    setTimeout(function(){
                        fnRequest();
                    },3000);
                }
                else{
                    fnRequest();
                }
            }
        };
        fn();
    },

    startGame:function(){
        this.lblErr.string += "预加载资源...\n";
        this.initMgr();
        ComponentsUtils.preloadRes();
        cc.director.preloadScene('mainScene', function() {
            this.gotoNextScene();         
        }.bind(this));  
    },

        //切换场景
    gotoNextScene:function(){
        this.lblErr.string += "进入游戏\n";
        this.labPercent.string = "100%";
        this.updateBar.progress = 1;
        this._isLoading = false;
        cc.director.loadScene("mainScene");
        cc.loader.onComplete = null;
    },

    // use this for initialization
    onLoad: function () {
        CL.HTTP = require("Http");
        //PlatformUtils.doLoadResDone();  
        this.lblErr.node.active = false;
        this._timer = 0;
        this.manifestUrl = cc.url.raw("resources/config/project.manifest");
        this.startUpdate();

        this.node.on('playEnd', function (event) {
            event.stopPropagation();
            this.labLog.string = "初始化加载资源...";
            this.lblErr.string += "初始化公共数据...\n";
            cc.director.preloadScene('mainScene', function() {
            });
            this.getServerUrlList();
        }.bind(this));
        
         //this.node.runAction(cc.sequence(cc.delayTime(5), cc.callFunc(function(){//延迟3s进行加载
            this.aniLogin.play('ani_login_effect');//开场动画
         //}.bind(this))));
         //隐藏FPS
         cc.director.setDisplayStats(false);
         //降低FPS
         cc.game.setFrameRate(40);
    },

    onDestroy: function () {
        if (this._updateListener) {
            cc.eventManager.removeListener(this._updateListener);
            this._updateListener = null;
        }
        if (this._am && !cc.sys.ENABLE_GC_FOR_NATIVE_OBJECTS) {
            this._am.release();
        }
    }

});
